﻿#include "ItemBase.h"
#include <math.h>
#include <QtDebug>
#include <QThread>
#include <QDebug>
#include <QtMath>


qreal ItemBase::contrSize = 8;
QMap<DefineItemType,QString> ItemBase::mapItemTypeName = {{DIT_Circle, QStringLiteral("圆")},
                                                           {DIT_CircleC, QStringLiteral("同心圆")},
                                                           {DIT_Rect, QStringLiteral("矩形")},
                                                           {DIT_RectR, QStringLiteral("旋转矩形")},
                                                           {DIT_Polygon, QStringLiteral("多边形")},
                                                           {DIT_Caliper, QStringLiteral("卡尺")},
                                                           {DIT_Line, QStringLiteral("直线")},
                                                           {DIT_Point, QStringLiteral("锚点")}};
//点道直线的距离
//************************************
// Method:    计算一个点一条直线的垂直距离;
// Returns:   qreal 返回垂直距离;
// Parameter: const QPointF & pt1  直线的第一个点;
// Parameter: const QPointF & pt2  直线的第二个点;
// Parameter: const QPointF pt3  目标点;
//************************************
qreal caculateCrossLengthPtToLine(const QPointF& pt1, const QPointF& pt2, const QPointF pt3)
{
    // 直线垂直的情况;
    if (pt1.x() == pt2.x()){
        return pt3.x() - pt1.x();
    }else{
        qreal angle = QLineF(pt1, pt2).angleTo(QLineF(pt1, pt3));
        qreal leng = sin(angle / 180 * M_PI) * (QLineF(pt1, pt3).length());
        return leng;
    }
}
QPointF caculateThirdPtFromTwoPoint(const QPointF& pt1, const QPointF& pt2, const double nLength, const double nAngle)
{
    double x1 = pt1.x();
    double y1 = pt1.y();
    double x2 = pt2.x();
    double y2 = pt2.y();
    double x3 = 0.0, y3 = 0.0;
    x3 = x1 + nLength * cos(double(atan2(y2 - y1, x2 - x1)) - nAngle);
    y3 = y1 + nLength * sin(double(atan2(y2 - y1, x2 - x1)) - nAngle);
    return QPointF(x3, y3);
}

ItemBase::ItemBase(QPointF p, DefineItemType type)
    :itemType(type)
    ,center(p)
{
    setHandlesChildEvents(false);//设置后才能将事件传递到子元素
    fillColor = QColor(0, 160, 230, 50); //填充颜色
    thisPen = QPen(QColor(0, 100, 200), 3);
    //模式选择 自定义模式用于显示亚像素轮廓和Region  不设定任何属性
    if (type != DIT_AutoItem){
        this->setFlags(QGraphicsItem::ItemIsSelectable |
                       QGraphicsItem::ItemIsMovable |
                       QGraphicsItem::ItemIsFocusable);
    }
}

void ItemBase::focusInEvent(QFocusEvent* event)
{
    Q_UNUSED(event);
    thisPen.setColor(QColor(0, 180, 0));
    for (int i = 0; i < controlList.length(); i++){
        controlList[i]->setVisible(true);
        //缩放控制点尺寸
        controlList[i]->setScale(1 / scale);
    }
}

void ItemBase::focusOutEvent(QFocusEvent* event)
{
    Q_UNUSED(event);
    thisPen.setColor(QColor(0, 100, 200));
    for (int i = 0; i < controlList.length(); i++){
        controlList[i]->setVisible(false);
    }
}

void ItemBase::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    painter->save();
    painter->setBrush(Qt::NoBrush);
    QFont font;
    font.setPointSizeF(15 / scale); //字体大小
    painter->setFont(font);
    painter->setPen(Qt::black);
    painter->drawText(controlList[0]->getCurPoint() + QPointF(-contrSize / scale, -(contrSize + 3) / scale), itemDescribe);
    painter->restore();
    //子类绘制时状态
    thisPen.setWidthF(3 / scale);
    painter->setPen(thisPen);
}

//******绘制结果数据******
ItemDraw::ItemDraw() :ItemBase(QPointF(0, 0), DIT_AutoItem)
{
    returnRec = QRectF(0, 0, 10000, 10000);
}

void ItemDraw::addLine(QLineF line)
{
    lineList.push_back(line);
}

void ItemDraw::addCircle(QPointF center, float radius)
{
    circleList << QRectF(center.x() - radius, center.y() - radius, radius * 2, radius * 2);
}
void ItemDraw::addRect(QRectF rect)
{
    rectList << rect;
}
void ItemDraw::addRegion(QVector<QPointF> &region)
{
    if(region.size() < 3)
        return;
    for(int i = 0; i < region.size() - 1; ++i){
        roiList.push_back(QLineF(region.at(i), region.at(i + 1)));
    }
    roiList.push_back(QLineF(region.at(region.size() - 1), region.at(0)));
}

void ItemDraw::addXld(QVector<QPointF> &xld)
{
    if(xld.size() < 3)
        return;
    for(int i = 0; i < xld.size() - 1; ++i){
        xldList.push_back(QLineF(xld.at(i), xld.at(i + 1)));
    }
}

QPolygonF getRectVertex(const QPointF center,float phi,float len1,float len2)
{
    QPointF a, b, c, d;
    a.setX(center.x() + len1 * cos(phi) - len2 * sin(phi));
    a.setY(center.y() - len1 * sin(phi) - len2 * cos(phi));

    b.setX(center.x() - len1 * cos(phi) - len2 * sin(phi));
    b.setY(center.y() + len1 * sin(phi) - len2 * cos(phi));

    c.setX(center.x() - len1 * cos(phi) + len2 * sin(phi));
    c.setY(center.y() + len1 * sin(phi) + len2 * cos(phi));

    d.setX(center.x() + len1 * cos(phi) + len2 * sin(phi));
    d.setY(center.y() - len1 * sin(phi) + len2 * cos(phi));

    return QPolygonF() << a << b << c << d;
}

void ItemDraw::addRectR(QPointF center, double phi, double len1, int len2)
{
    QPolygonF rectR = getRectVertex(center, phi, len1, len2);
    rectRList << rectR;
}
void ItemDraw::addPoint(QPointF point)
{
    pointList << point;
}

void ItemDraw::addText(ItemDrawText txt)
{
    txtList << txt;
}

void ItemDraw::clearAll()
{
    lineList.clear();
    roiList.clear();
    circleList.clear();
    rectList.clear();
    pointList.clear();
    rectRList.clear();
    txtList.clear();
}
void ItemDraw::refresh()
{
    this->update();
}

QRectF ItemDraw::boundingRect() const
{
    if (!returnRec.isValid()) {
        return QRectF();
    }
    return returnRec;
}

void ItemDraw::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    double drawWidth = 1 / scale;
    // qDebug() << "drawWidth" << drawWidth;
    thisPen.setWidthF(drawWidth);
    thisPen.setColor(QColor(255, 0, 0));
    painter->setPen(thisPen);
    if(!lineList.empty()){
        painter->drawLines(lineList);
    }
    if(!roiList.empty()){
        painter->drawLines(roiList);
    }

    if(!xldList.empty()){
        painter->drawLines(xldList);
    }
    if(!rectList.empty()){
        painter->drawRects(rectList);
    }
    for (auto item : circleList){
        painter->drawEllipse(item);
    }
    for(auto item : pointList){
        painter->drawLine(item + QPointF(-3,-3), item + QPointF(3,3));
        painter->drawLine(item + QPointF(-3,3), item + QPointF(3,-3));
    }
    for(auto item : rectRList){
        painter->drawPolygon(item);
    }
    for(auto item : txtList){
        painter->drawText(item.point, item.text);
    }
}

#pragma region 矩形
ItemRect::ItemRect(qreal x, qreal y, qreal width, qreal height)
    :ItemBase(QPointF(x + width / 2, y + height / 2), DIT_Rect)
{
    controlList << new ControlItem(this, QPointF(x, y), CPT_Control);
    controlList << new ControlItem(this, QPointF(x + width, y), CPT_Control);
    controlList << new ControlItem(this, QPointF(x + width, y + height), CPT_Control);
    controlList << new ControlItem(this, QPointF(x, y + height), CPT_Control);
}

ItemRect::ItemRect():ItemBase(QPointF(0, 0), DIT_Rect)
{
    this->setVisible(false);
    nextIndexPoint = 0;
    controlList << new ControlItem(this, QPointF(0, 0), CPT_Control);
    controlList << new ControlItem(this, QPointF(0, 0), CPT_Control);
    controlList << new ControlItem(this, QPointF(0, 0), CPT_Control);
    controlList << new ControlItem(this, QPointF(0, 0), CPT_Control);
}

QRectF ItemRect::boundingRect() const
{
    return  QRectF(controlList[0]->getCurPoint(), controlList[2]->getCurPoint());
}

bool ItemRect::itemUpdate(int index)
{
    QPointF pf = controlList[index]->getCurPoint();
    //角点分情况
    switch (index)
    {
    case 0:
        controlList[1]->setPoint(QPointF(controlList[1]->getCurPoint().x(), pf.y()));
        controlList[3]->setPoint(QPointF(pf.x(), controlList[3]->getCurPoint().y()));
        break;
    case 1:
        controlList[0]->setPoint(QPointF(controlList[0]->getCurPoint().x(), pf.y()));
        controlList[2]->setPoint(QPointF(pf.x(), controlList[2]->getCurPoint().y()));
        break;
    case 2:
        controlList[3]->setPoint(QPointF(controlList[3]->getCurPoint().x(), pf.y()));
        controlList[1]->setPoint(QPointF(pf.x(), controlList[1]->getCurPoint().y()));
        break;
    case 3:
        controlList[2]->setPoint(QPointF(controlList[2]->getCurPoint().x(), pf.y()));
        controlList[0]->setPoint(QPointF(pf.x(), controlList[0]->getCurPoint().y()));
        break;
    default:
        break;
    }
    //中心点
    center = (controlList[0]->getCurPoint() + controlList[2]->getCurPoint()) / 2;
    return true;
}

void ItemRect::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    QRectF ret(controlList[0]->getCurPoint(), controlList[2]->getCurPoint());
    painter->drawRect(ret);
}


void ItemRect::getDefObject(DefRect& rect)
{
    rect = getDefObject();
}

DefRect ItemRect::getDefObject()
{
    DefRect rect;
    QPointF getRec = this->mapToScene(controlList[0]->x(), controlList[0]->y());
    QPointF getRec1 = this->mapToScene(controlList[2]->x(), controlList[2]->y());
    rect.x = qMin(getRec.x(), getRec1.x());
    rect.y = qMin(getRec.y(), getRec1.y());
    rect.width = abs(getRec1.x() - rect.x);
    rect.height = abs(getRec1.y() - rect.y);
    return rect;
}

void ItemRect::onPointPush(QPointF p)
{
    if(nextIndexPoint == 0){
        controlList[0]->setPoint(p);
        controlList[1]->setPoint(p);
        controlList[2]->setPoint(p);
        controlList[3]->setPoint(p);
    }
    this->update();
    nextIndexPoint++;
    this->setVisible(true);
}

void ItemRect::onPointMove(QPointF p)
{
    QPointF pointTL = controlList.at(0)->getCurPoint();
    controlList[1]->setPoint(QPointF(p.x(), pointTL.y()));
    controlList[2]->setPoint(p);
    controlList[3]->setPoint(QPointF(pointTL.x(), p.y()));
}

#pragma endregion

#pragma region 旋转矩形
ItemRectR::ItemRectR(qreal x, qreal y, qreal lenth1, qreal lenth2, qreal Pi)
    :ItemBase(QPointF(x, y), DIT_RectR)
{
    phi = Pi;
    this->lenth1 = lenth1;
    this->lenth2 = lenth2;
    qreal s = sin(-phi);
    qreal c = cos(-phi);
    pa1 = center + QPointF(lenth1 * c, lenth1 * s);
    pa2 = center + QPointF(-lenth2 * s, lenth2 * c);
    pArrow = center + QPointF((lenth1 + 20) * c, (lenth1 + 20) * s);
    //中心线控制点
    controlList << new ControlItem(this, pa1, CPT_Control);
    controlList << new ControlItem(this, pa2, CPT_Control);
}

ItemRectR::ItemRectR():ItemBase(QPointF(0, 0), DIT_RectR)
{
    this->setVisible(false);
    phi = 0;
    lenth1 = 0;
    lenth2 = 0;
    pa1 = center;
    pa2 = center;
    pArrow = center;
    //中心线控制点
    controlList << new ControlItem(this, center, CPT_Control);
    controlList << new ControlItem(this, center, CPT_Control);
    nextIndexPoint = -1;
}


QRectF ItemRectR::boundingRect() const
{
    QPolygonF rect;
    rect << QPointF(center.x() + lenth1, center.y() + lenth2);
    rect << QPointF(center.x() + lenth1, center.y() - lenth2);
    rect << QPointF(center.x() - lenth1, center.y() - lenth2);
    rect << QPointF(center.x() - lenth1, center.y() + lenth2);

    QTransform transF;
    transF.translate(center.x(), center.y());
    transF.rotate(phi * 180 / M_PI);
    transF.translate(-center.x(), -center.y());
    QPolygonF rectR = transF.map(rect);

    QList<float> lstX, lstY;
    lstX << rectR[0].x() << rectR[1].x()
         << rectR[2].x() << rectR[3].x();
    lstY << rectR[0].y() << rectR[1].y()
         << rectR[2].y() << rectR[3].y();

    float minX = *std::min_element(std::begin(lstX), std::end(lstX));
    float maxX = *std::max_element(std::begin(lstX), std::end(lstX));
    float minY = *std::min_element(std::begin(lstY), std::end(lstY));
    float maxY = *std::max_element(std::begin(lstY), std::end(lstY));

    return QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
    // QPolygonF rect;
    // rect << QPointF(center.x() + lenth1, center.y() + lenth2)
    //      << QPointF(center.x() + lenth1, center.y() - lenth2)
    //      << QPointF(center.x() - lenth1, center.y() - lenth2)
    //      << QPointF(center.x() - lenth1, center.y() + lenth2);

    // QTransform transF;
    // transF.translate(center.x(), center.y());
    // transF.rotateRadians(phi); // 使用弧度旋转

    // QPolygonF rectR = transF.map(rect);
    // return rectR.boundingRect();
}

bool ItemRectR::itemUpdate(int index)
{
    QPointF pf = controlList[index]->getCurPoint();
    qreal dx = pf.x() - center.x();
    qreal dy = pf.y() - center.y();
    if(index == 0){
        if (dx >= 0 && dy < 0){
            phi = atan2((-1) * (dy), dx);
        }else if (dx < 0 && dy < 0){
            phi = atan2((-1) * dy, dx);
        }else if (dx < 0 && dy >= 0){
            phi = atan2((-1) * dy, dx);
        }else if (dx >= 0 && dy >= 0){
            phi = M_PI * 2 - atan2(dy, dx);
        }
        // phi = atan2(-dy, dx); // atan2 返回 -π 到 π
        qreal s = sin(-phi);
        qreal c = cos(-phi);
        lenth1 = sqrt(dx * dx + dy * dy);
        pa1 = center + QPointF(lenth1 * c, lenth1 * s);
        pArrow = center + QPointF((lenth1 + 20) * c, (lenth1 + 20) * s);
        controlList[0]->setPoint(pa1);
        pa2 = caculateThirdPtFromTwoPoint(center, controlList[0]->getCurPoint(), lenth2, posControlPoint2);
        controlList[1]->setPoint(pa2);
    } else if(index == 1){
        lenth2 = sqrt(dx * dx + dy * dy);
        pa2 = caculateThirdPtFromTwoPoint(center, controlList[0]->getCurPoint(), lenth2, posControlPoint2);
        controlList[1]->setPoint(pa2);
    }
    return true;
}

void ItemRectR::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    //画角度方向线
    painter->drawLine(pArrow, pa1);
    //绘制方向箭头
    float l = 15.0;//箭头长度
    double atn1 = atan2((pArrow.y() - pa1.y()), (pArrow.x() - pa1.x()));
    double atn2 = atan2((pArrow.x() - pa1.x()), (pArrow.y() - pa1.y()));
    QPointF Arrow1(pArrow.x() - l * cos(atn1 - 0.5), pArrow.y() - l * sin(atn1 - 0.5));
    QPointF Arrow2(pArrow.x() - l * sin(atn2 - 0.5), pArrow.y() - l * cos(atn2 - 0.5));
    painter->drawLine(pArrow, Arrow1);
    painter->drawLine(pArrow, Arrow2);
    //绘制旋转矩形
    painter->save();
    painter->translate(center);
    painter->rotate(-phi * 180 / M_PI);
    painter->drawRect(QRectF(-lenth1, -lenth2, lenth1 * 2, lenth2 * 2));
    painter->restore();
}
void ItemRectR::getDefObject(DefRectR& rectR)
{
    rectR = getDefObject();
}
DefRectR ItemRectR::getDefObject()
{
    DefRectR rectR;
    rectR.x = this->mapToScene(center).x();
    rectR.y = this->mapToScene(center).y();
    rectR.phi = phi;
    rectR.length1 = lenth1;
    rectR.length2 = lenth2;
    return rectR;
}

void ItemRectR::onPointPush(QPointF p)
{
    if(nextIndexPoint == -1){
        center = p;
    }
    this->update();
    nextIndexPoint++;
    this->setVisible(true);
}

void ItemRectR::onPointMove(QPointF p)
{
    if(nextIndexPoint >= 0){
        if(nextIndexPoint == 0){
            controlList[nextIndexPoint]->setPoint(p);
        } else if(nextIndexPoint == 1){
            double dis = caculateCrossLengthPtToLine(center, controlList[0]->getCurPoint(), p);
            QPointF point2 = caculateThirdPtFromTwoPoint(center, controlList[0]->getCurPoint(), abs(dis), posControlPoint2);
            controlList[nextIndexPoint]->setPoint(point2);
        }
        itemUpdate(nextIndexPoint);
        this->update();
    }
}
#pragma endregion

#pragma region 多边形
ItemPolygon::ItemPolygon(QList<QPointF> lstPoint):ItemBase(QPointF(0, 0), DIT_Polygon)
{
    for(int i = 0; i < lstPoint.size(); ++i){
        controlList << new ControlItem(this, lstPoint.at(i), CPT_Control);
    }
    center = getCentroPoint(lstPoint);
    getMaxLength();
    isPushFinish = true;
}

ItemPolygon::ItemPolygon():ItemBase(QPointF(0, 0), DIT_Polygon)
{
    isPushFinish = false;
}

QPointF ItemPolygon::getCentroPoint(QList<QPointF> list)
{
    qreal x = 0;
    qreal y = 0;
    for (auto& temp : list){
        x += temp.x();
        y += temp.y();
    }
    x = x / list.size();
    y = y / list.size();
    return QPointF(x, y);
}

void ItemPolygon::getMaxLength()
{
    QVector<qreal> vec;
    vec.reserve(200);
    vec.clear();
    for (int i = 0; i < controlList.length(); i++){
        qreal dis = sqrt(pow(center.x() - controlList[i]->x(), 2) + pow(center.y() - controlList[i]->y(), 2));
        vec.append(dis);
    }
    qreal ret = 0;
    for (auto& temp : vec){
        if (temp > ret) {
            ret = temp;
        }
    }
    radius = ret;
}

void ItemPolygon::onPointPush(QPointF p)
{
    auto tmp = new ControlItem(this, p, CPT_Control);
    tmp->setVisible(true);
    controlList << tmp;
    this->update();
}
void ItemPolygon::onPointMove(QPointF p)
{
    controlList.last()->setPoint(p);
    this->update();
}
void ItemPolygon::onCreateFinish()
{
    isPushFinish = true;
    QList<QPointF> list;
    for(int i = 0; i < controlList.length(); i++){
        list << controlList[i]->getCurPoint();
    }
    center = getCentroPoint(list);
    this->update();
    ItemBase::onCreateFinish();
}

QRectF ItemPolygon::boundingRect() const
{
    QList<float> lstX;
    QList<float> lstY;
    lstX.clear();
    lstY.clear();
    for (int i = 0; i < controlList.length(); i++){
        lstX << controlList[i]->getCurPoint().x();
        lstY << controlList[i]->getCurPoint().y();
    }
    float minX = *std::min_element(std::begin(lstX), std::end(lstX));
    float maxX = *std::max_element(std::begin(lstX), std::end(lstX));
    float minY = *std::min_element(std::begin(lstY), std::end(lstY));
    float maxY = *std::max_element(std::begin(lstY), std::end(lstY));
    return QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
}

bool ItemPolygon::itemUpdate(int index)
{
    Q_UNUSED(index);
    QList<QPointF> list;
    list.clear();
    for(int i = 0; i < controlList.length(); i++){
        list << controlList[i]->getCurPoint();
    }
    center = getCentroPoint(list);
    return true;
}

void ItemPolygon::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    if(isPushFinish){
        for (int i = 0; i < controlList.length() - 1; i++){
            painter->drawLine(controlList[i]->getCurPoint(), controlList[i + 1]->getCurPoint());
        }
        painter->drawLine(controlList[controlList.length() - 1]->getCurPoint(), controlList[0]->getCurPoint());
    }else{
        for (int i = 0; i < controlList.length() - 1; i++){
            painter->drawLine(controlList[i]->getCurPoint(), controlList[i + 1]->getCurPoint());
        }
    }
}

void ItemPolygon::getDefObject(DefPolygon& defPolygon)
{
    defPolygon = getDefObject();
}
DefPolygon ItemPolygon::getDefObject()
{
    DefPolygon obj;
    QList<QPointF> list_p;
    list_p.clear();
    for (int i = 0; i < controlList.length(); i++){
        list_p.append(mapToScene(controlList[i]->getCurPoint()));
    }
    obj.points = list_p;
    return obj;
}
#pragma endregion

#pragma region 圆
ItemCircle::ItemCircle(qreal x, qreal y, qreal R) :ItemBase(QPointF(x, y), DIT_Circle)
{
    radius = R;
    controlList << new ControlItem(this, center + QPointF(R, 0), CPT_Control);
}

ItemCircle::ItemCircle():ItemBase(QPointF(0, 0), DIT_Circle)
{
    this->setVisible(false);
    radius = 0;
    nextIndexPoint = -1;
    controlList << new ControlItem(this, center, CPT_Control);
}

QRectF ItemCircle::boundingRect() const
{
    return QRectF(center.x() - radius, center.y() - radius, radius * 2, radius * 2);
}

bool ItemCircle::itemUpdate(int index)
{
    QPointF Pf = controlList[index]->getCurPoint();
    QPointF tmp = Pf - center;
    radius = sqrt(tmp.x() * tmp.x() + tmp.y() * tmp.y());
    return true;
}

void ItemCircle::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    painter->drawEllipse(QRectF(center.x() - radius, center.y() - radius, radius * 2, radius * 2));
}

void ItemCircle::getDefObject(DefCircle& cir)
{
    cir = getDefObject();
}
DefCircle ItemCircle::getDefObject()
{
    DefCircle cir;
    cir.x = this->mapToScene(center).x();;
    cir.y = this->mapToScene(center).y();;
    cir.radius = radius;
    return cir;
}
void ItemCircle::onPointPush(QPointF p)
{
    if(nextIndexPoint == -1){
        center = p;
    }
    this->update();
    this->setVisible(true);
    nextIndexPoint++;
}

void ItemCircle::onPointMove(QPointF p)
{
    controlList[0]->setPoint(p);
    itemUpdate(0);
    this->update();
}
#pragma endregion

#pragma region 同心圆
ItemCircleC::ItemCircleC(qreal x, qreal y, qreal radiusMin, qreal radiusMax) :ItemBase(QPointF(x, y), DIT_CircleC)
{
    radiusOuter = std::max(radiusMin, radiusMax);
    radiusInner = std::min(radiusMin, radiusMax);
    controlList << new ControlItem(this, center + QPointF(radiusInner, 0), CPT_Control);
    controlList << new ControlItem(this, center + QPointF(radiusOuter, 0), CPT_Control);
}

ItemCircleC::ItemCircleC():ItemBase(QPointF(0, 0), DIT_CircleC)
{
    this->setVisible(false);
    radiusOuter = 0;
    radiusInner = 0;
    nextIndexPoint = -1;
    controlList << new ControlItem(this, center, CPT_Control);
    controlList << new ControlItem(this, center, CPT_Control);
}

QRectF ItemCircleC::boundingRect() const
{
    return QRectF(center.x() - radiusOuter, center.y() - radiusOuter, radiusOuter * 2, radiusOuter * 2);
}

bool ItemCircleC::itemUpdate(int index)
{
    QPointF pf0 = controlList[0]->getCurPoint();
    QPointF tmp0 = pf0 - center;
    qreal r0 = sqrt(pow(tmp0.x(), 2) + pow(tmp0.y(), 2));

    QPointF pf1 = controlList[1]->getCurPoint();
    QPointF tmp1 = pf1 - center;
    qreal r1 = sqrt(pow(tmp1.x(), 2) + pow(tmp1.y(), 2));

    radiusInner = std::min(r0, r1);
    radiusOuter = std::max(r0, r1);
    return true;
}

void ItemCircleC::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    QPainterPath pth;
    pth.addEllipse(QRectF(center.x() - radiusInner, center.y() - radiusInner, radiusInner * 2, radiusInner * 2));
    pth.addEllipse(QRectF(center.x() - radiusOuter, center.y() - radiusOuter, radiusOuter * 2, radiusOuter * 2));
    painter->setBrush(QBrush(fillColor));
    painter->drawPath(pth);
}

void ItemCircleC::getDefObject(DefCircleC& CCir)
{
    CCir = getDefObject();
}
DefCircleC ItemCircleC::getDefObject()
{
    DefCircleC CCir;
    CCir.x = this->mapToScene(center).x();;
    CCir.y = this->mapToScene(center).y();;
    CCir.rSmall = radiusInner;
    CCir.rBig = radiusOuter;
    return CCir;
}
void ItemCircleC::onPointPush(QPointF p)
{
    if(nextIndexPoint == -1){
        center = p;
        controlList[0]->setPoint(p);
        controlList[1]->setPoint(p);
        itemUpdate(nextIndexPoint);
    }
    this->update();
    nextIndexPoint++;
    this->setVisible(true);
}

void ItemCircleC::onPointMove(QPointF p)
{
    if(nextIndexPoint >= 0){
        if(nextIndexPoint == 0){
            controlList[0]->setPoint(p);
            controlList[1]->setPoint(p);
        } else if(nextIndexPoint == 1){
            controlList[nextIndexPoint]->setPoint(p);
        }
        itemUpdate(nextIndexPoint);
        this->update();
    }
}
#pragma endregion


#pragma region 卡尺
ItemCaliper::ItemCaliper(qreal x1, qreal y1, qreal x2, qreal y2, qreal height)
    :ItemBase(QPointF((x1 + x2) / 2, (y1 + y2) / 2), DIT_Caliper)
{	
    pointStart = QPointF(x1, y1);
    pointEnd = QPointF(x2, y2);
    controlList << new ControlItem(this, pointStart, CPT_Control);
    controlList << new ControlItem(this, pointEnd, CPT_Control);
    QPointF point2 = caculateThirdPtFromTwoPoint(center, controlList[1]->getCurPoint(), height, M_PI_2);
    controlList << new ControlItem(this, point2, CPT_Control);

    qreal dx = center.x() - pointEnd.x();
    qreal dy = center.y() - pointEnd.y();
    this->length = sqrt(dx * dx + dy * dy);
    this->height = height;

    if (dx >= 0 && dy < 0){
        phi = atan2((-1) * (dy), dx);
    }else if (dx < 0 && dy < 0){
        phi = atan2((-1) * dy, dx);
    }else if (dx < 0 && dy >= 0){
        phi = M_PI * 2 + atan2((-1) * dy, dx);
    }else if (dx >= 0 && dy >= 0){
        phi = M_PI * 2 - atan2(dy, dx);
    }

}
ItemCaliper::ItemCaliper()
    :ItemBase(QPointF(0, 0), DIT_Caliper)
{
    controlList << new ControlItem(this, center, CPT_Control);
    controlList << new ControlItem(this, center, CPT_Control);
    controlList << new ControlItem(this, center, CPT_Control);
    this->setVisible(false);
    pointStart = QPointF(0, 0);
    pointEnd = QPointF(0, 0);
    this->height = 0;
    phi = 0;
    this->length = 0;
    nextIndexPoint = 0;
}

QRectF ItemCaliper::boundingRect() const
{
    float lenth1 = std::max(length, height) / 2;
    float lenth2 = std::min(length, height) / 2;

    QPolygonF rect;
    rect << QPointF(center.x() + lenth1, center.y() + lenth2);
    rect << QPointF(center.x() + lenth1, center.y() - lenth2);
    rect << QPointF(center.x() - lenth1, center.y() - lenth2);
    rect << QPointF(center.x() - lenth1, center.y() + lenth2);

    QTransform transF;
    transF.translate(center.x(), center.y());
    transF.rotate(phi * 180 / M_PI);
    transF.translate(-center.x(), -center.y());
    QPolygonF rotateRect = transF.map(rect);

    QList<float> lstX, lstY;
    lstX << rotateRect[0].x() << rotateRect[1].x()
         << rotateRect[2].x() << rotateRect[3].x();
    lstY << rotateRect[0].y() << rotateRect[1].y()
         << rotateRect[2].y() << rotateRect[3].y();

    float minX = *std::min_element(std::begin(lstX), std::end(lstX));
    float maxX = *std::max_element(std::begin(lstX), std::end(lstX));
    float minY = *std::min_element(std::begin(lstY), std::end(lstY));
    float maxY = *std::max_element(std::begin(lstY), std::end(lstY));

    return QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
}

bool ItemCaliper::itemUpdate(int index)
{
    if (index == 0){
        pointStart = controlList[index]->getCurPoint();
    }else if (index == 1){
        pointEnd = controlList[index]->getCurPoint();
    }else if (index == 2){
        QPointF pf = controlList[index]->getCurPoint();
        height = abs(caculateCrossLengthPtToLine(controlList[0]->getCurPoint(), controlList[1]->getCurPoint(), pf));
    }
    center = QPointF((pointStart.x() + pointEnd.x()) / 2, (pointStart.y() + pointEnd.y()) / 2);
    qreal dx = center.x() - pointEnd.x();
    qreal dy = center.y() - pointEnd.y();
    length = sqrt(dx * dx + dy * dy);

    if (dx >= 0 && dy < 0){
        phi = atan2((-1) * (dy), dx);
    }else if (dx < 0 && dy < 0){
        phi = atan2((-1) * dy, dx);
    }else if (dx < 0 && dy >= 0){
        phi = M_PI * 2 + atan2((-1) * dy, dx);
    }else if (dx >= 0 && dy >= 0){
        phi = M_PI * 2 - atan2(dy, dx);
    }

    QPointF point2 = caculateThirdPtFromTwoPoint(center, controlList[1]->getCurPoint(), height, M_PI_2);
    controlList[2]->setPoint(point2);
    return true;
}

void ItemCaliper::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    //绘制分割线
    // painter->setPen(QPen(QColor(0, 0, 255, 255), 3));
    //绘制方向箭头
    float l = 22.0;//箭头长度
    painter->save();
    painter->translate(center);
    painter->setBrush(QBrush(fillColor));
    painter->rotate(-phi * 180 / M_PI);
    QRect rect(-length, -height, length * 2, height * 2);
    painter->drawRect(rect);

    QPointF arrow1 = QPointF(rect.topLeft().x() - l * cos(M_PI_4), rect.topLeft().y() + l * sin(M_PI_4));
    QPointF arrow2 = QPointF(rect.topLeft().x() + l * sin(M_PI_4), rect.topLeft().y() + l * cos(M_PI_4));
    painter->drawLine(rect.topLeft(), arrow1);
    painter->drawLine(rect.topLeft(), arrow2);

    QPointF arrow3 = QPointF(rect.topRight().x() - l * cos(M_PI_4), rect.topRight().y() + l * sin(M_PI_4));
    QPointF arrow4 = QPointF(rect.topRight().x() + l * sin(M_PI_4), rect.topRight().y() + l * cos(M_PI_4));
    painter->drawLine(rect.topRight(), arrow3);
    painter->drawLine(rect.topRight(), arrow4);

    painter->restore();
}

void ItemCaliper::getDefObject(DefCaliper& cp)
{
    cp = getDefObject();
}
DefCaliper ItemCaliper::getDefObject()
{
    DefCaliper CP;
    QPointF start = this->mapToScene(pointStart);
    QPointF end = this->mapToScene(pointEnd);
    CP.x1 = start.x();
    CP.y1 = start.y();
    CP.x2 = end.x();
    CP.y2 = end.y();
    CP.height = height;
    return CP;
}
void ItemCaliper::onPointPush(QPointF p)
{
    if(nextIndexPoint == 0){
        controlList[0]->setPoint(p);
        controlList[1]->setPoint(p);
        controlList[2]->setPoint(p);
        center = p;
        pointStart = p;
        pointEnd = p;
        height = 0;
        phi = 0;
        length = 0;
        itemUpdate(nextIndexPoint);
    }
    this->update();
    nextIndexPoint++;
    this->setVisible(true);
}

void ItemCaliper::onPointMove(QPointF p)
{
    if(nextIndexPoint > 0){
        if(nextIndexPoint == 1){
            center = (controlList[0]->getCurPoint() + p) / 2;
            controlList[1]->setPoint(p);
            controlList[2]->setPoint(center);
        } else if(nextIndexPoint == 2){
            double dis = caculateCrossLengthPtToLine(controlList[0]->getCurPoint(), controlList[1]->getCurPoint(), p);
            QPointF point2 = caculateThirdPtFromTwoPoint(center, controlList[1]->getCurPoint(), abs(dis), M_PI_2);
            controlList[nextIndexPoint]->setPoint(point2);
        }
        itemUpdate(nextIndexPoint);
        this->update();
    }
}
#pragma endregion

#pragma region 直线
ItemLine::ItemLine(qreal x1, qreal y1, qreal x2, qreal y2)
    :ItemBase(QPointF((x1 + x2) / 2, (y1 + y2) / 2), DIT_Line)
{
    pointStart = QPointF(x1, y1);
    pointEnd = QPointF(x2, y2);
    controlList << new ControlItem(this, pointStart, CPT_Control);
    controlList << new ControlItem(this, pointEnd, CPT_Control);
}
ItemLine::ItemLine() :ItemBase(QPointF(0, 0), DIT_Line)
{
    this->setVisible(false);
    pointStart = center;
    pointEnd = center;
    controlList << new ControlItem(this, pointStart, CPT_Control);
    controlList << new ControlItem(this, pointEnd, CPT_Control);
    nextIndexPoint = 0;
}

QRectF ItemLine::boundingRect() const
{
    return QRectF(pointStart, pointEnd);
}

bool ItemLine::itemUpdate(int index)
{
    if(index == 0){
        pointStart = controlList[index]->getCurPoint();
    }else if (index == 1){
        pointEnd = controlList[index]->getCurPoint();
    }
    center = (pointStart + pointEnd) / 2;
    return true;
}

void ItemLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    painter->drawLine(pointStart, pointEnd);
}
void ItemLine::getDefObject(DefLine& line)
{
    line = getDefObject();
}
DefLine ItemLine::getDefObject()
{
    QPointF start = this->mapToScene(pointStart);
    QPointF end = this->mapToScene(pointEnd);
    DefLine line;
    line.x1 = start.x();
    line.y1 = start.y();
    line.x2 = end.x();
    line.y2 = end.y();
    return line;
}
void ItemLine::onPointPush(QPointF p)
{
    if(nextIndexPoint == 0){
        center = p;
        pointStart = p;
        pointEnd = p;
        controlList[0]->setPoint(pointStart);
        controlList[1]->setPoint(pointEnd);
        itemUpdate(nextIndexPoint);
    }
    this->update();
    nextIndexPoint++;
    this->setVisible(true);
}

void ItemLine::onPointMove(QPointF p)
{
    if(nextIndexPoint > 0){
        controlList[nextIndexPoint]->setPoint(p);
        itemUpdate(nextIndexPoint);
    }
    this->update();
}
#pragma endregion

//**************************************锚点*********************************************************
ItemPoint::ItemPoint(qreal x, qreal y):ItemBase(QPoint(x,y),DIT_Point)
{
    controlList << new ControlItem(this, center, CPT_Control);
}
ItemPoint::ItemPoint(DefPoint defPoint):ItemBase(QPointF(defPoint.x, defPoint.y), DIT_Point)
{
    controlList << new ControlItem(this, center, CPT_Control);
}

ItemPoint::ItemPoint():ItemBase(QPoint(0, 0), DIT_Point)
{
    this->setVisible(false);
    controlList << new ControlItem(this, center, CPT_Control);
    nextIndexPoint = 0;
}

void ItemPoint::getDefObject(DefPoint& defPoint)
{
    defPoint = getDefObject();
}

DefPoint ItemPoint::getDefObject()
{
    QPointF start = this->mapToScene(center);
    DefPoint defPoint;
    defPoint.x = start.x();
    defPoint.y = start.y();
    return defPoint;
}

QRectF ItemPoint::boundingRect() const
{
    return QRectF(center - QPointF(ItemBase::contrSize * 2, ItemBase::contrSize * 2),
                  center + QPointF(ItemBase::contrSize * 2, ItemBase::contrSize * 2));
}

bool ItemPoint::itemUpdate(int index)
{
    center = controlList[index]->getCurPoint();
    return true;
}

void ItemPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    ItemBase::paint(painter, option, widget);
    painter->drawLine(center - QPointF(0, ItemBase::contrSize * 2),
                      center + QPointF(0, ItemBase::contrSize * 2));
    painter->drawLine(center - QPointF(ItemBase::contrSize * 2, 0),
                      center + QPointF(ItemBase::contrSize * 2, 0));
}
void ItemPoint::onPointPush(QPointF p)
{
    center = p;
    controlList[0]->setPoint(this->mapFromScene(center));
    itemUpdate(0);
    this->update();
    this->setVisible(true);
}

